home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / ddj0897.zip / OBJECTC.ASC < prev    next >
Text File  |  1997-06-20  |  8KB  |  277 lines

  1. _Dynamic Design Patterns in Objective-C_
  2. by William Grosso
  3.  
  4.  
  5. Listing One 
  6. //  From the header file -- define a pointer to member function for a method 
  7.     bool appBecameActiveCanBeCalled;
  8.     id (* appBecameActive) (id, SEL, id);
  9.  
  10. // From the .m (code) file (and heavily annotated)
  11. - (void) setDelegate: newDelegate
  12. {
  13.     SEL tokenizedMethodName; // the @selector compiler directive tokenizes 
  14.                              // the method name. 
  15. //  First, we check to see if we have a delegate and, if so, whether the new 
  16. //  delegate is from the same class; if both these are true, just return. 
  17.     if ((nil!=_internalDelegate) && ([newDelegate cisMemberOf: 
  18.                                               [_internalDelegate class]))
  19.     {
  20.         _internalDelegate = [newDelegate retain];   //delegate won't be freed
  21. return;
  22.     }
  23. // We need to explicitly check which methods our new delegate has implemented. 
  24.     _internalDelegate = [newDelegate retain];  //ensure delegate won't be freed
  25.     tokenizedMethodName=@selector(appBecameActive:);
  26.     if (YES==[ newDelegate respondsTo: tokenizedMethodName])
  27.     {
  28. //  syntax is [object memberFunction: argumentOne tag: argument2 ...]; We now
  29. //  know that the new delegate object implements appBecameActive. We will get 
  30. //  function pointer (for speed, might be calling this function often and 
  31. //  and therefore want to avoid rebinding the selector).  Usually, we wouldn't
  32. //  get the function pointer. 
  33. AppBecameActive=(id (*) (id,  SEL, id) 
  34. [_internalDelegate methodFor: tokenizedMethodName];
  35.         appBecameActiveCanBeCalled=YES;
  36.     }
  37. else
  38. {
  39. appBecameActiveCanBeCalled =NO;
  40.     }
  41. //  ....
  42. }
  43.  
  44.  
  45. Listing Two
  46. //  code in main application
  47. -  loadObscureClassFromDisk
  48. {
  49. //  Our goal is to find a requried class object (which we will return)
  50.  
  51.     Class classThatsNeeded;
  52. //  Has it been loaded ? Try to find the class object using a wrapper 
  53. //  function which encapsulates the run-time function objc_lookUpClass();
  54.     classThatsNeeded =NXClassFromString("ObscureClassName");
  55.     If (nil== classThatsNeeded)
  56.     {
  57. //  No class object. We need to load it. 
  58. //  Build a path name, relative to where application was installed by 
  59. //  concatenating a subdirectory name onto [[NXApp mainBundle] directory] 
  60.         char * fullPathDirectory;
  61.         ....
  62.         NXBundle * bundleForClass =[[NXBundle alloc] initForDirectory: 
  63.                                                           fullPathDirectory];
  64.         classThatsNeeded=[ bundleForClass classNamed:"ObscureClassName"];
  65.     }
  66.     return classThatsNeeded;
  67. }
  68.  
  69.  
  70. Listing Three
  71. //  code in an element
  72. - (bool) accept: aVisitor
  73. {
  74. //  Protocols are like interfaces in javathey define a set of methods. 
  75. //  Objects, when declared (in their header files), inherit from one concrete
  76. //  class and multiple protocols. This accept method checks whether the 
  77. //  visitor conformsTo (inherits from) a certain protocol declared earlier 
  78. //  or if the visitor is of a particular class. 
  79.     if (([aVisitor conformsTo: MyProtocol]) !! 
  80.                                        ([aVisitor isKindOf: acceptableClass]))
  81.     {
  82.         return [aVisitor visit: self];
  83.     }
  84.     return NO;
  85. }
  86. //  code in a visitor
  87. - visit: anElement
  88. {
  89. //  again, do type checking. Check whether element is an instance of a 
  90. //  specific class; if that fails, whether it inherits from some other class. 
  91. //  classOne and classTwo are declared previously. 
  92.     if ([anElement isMemberOf: classOne])
  93.     {
  94. //  perform some sequence of actions
  95.     }
  96.     else if ([anElement isKindOf: classTwo])
  97.     {
  98. //  perform some sequence of actions
  99.     }
  100. return NO;
  101. }
  102.  
  103. Listing Four
  104. template <Class T> CommandObject
  105. {
  106.     private: 
  107.         T& target
  108.         void (T::memberFunctionToCall)();
  109.     public:
  110.         CommandObject(T& theTarget, void (T::theMemberFunctionToCall)());
  111.         void Do();
  112. }
  113. //  comment: ask Don to finish this.
  114.  
  115.  
  116. Listing Five
  117. //  headers  --  Serializer implements
  118. - (void) writeInt: (id) value;
  119. - (void) writeFloat: (id) value;
  120. - (void) writeDouble: (id) value
  121. - (void) writeChar: (id) value
  122. - (void) writeObject: (id) value
  123.  
  124. //  Serializable implements
  125. - (void) serializeUsing: (Serializer *) serializerToUse;
  126. - (void) initWithDeserializer: (Deserialier *) deserializerWithMyState;
  127.  
  128. //  Serializer implements
  129. - (int) readInt;
  130. - (float) readFloat;
  131. - (double) readDouble;
  132. - (char) readChar;
  133. - (id) readObject;
  134.  
  135. //  from Serializer's Code
  136. - (void) writeObject: (id) value
  137. {
  138.     if (YES==[self objectAlreadyWritten: value])
  139.     {
  140. //  The object thas already been serialized. We just store the 
  141. //  internal uuid (so we can rebuild the object graph). 
  142.         [self storeReferenceToObject: value];
  143.     }
  144.     else
  145.     {
  146. //  first log that we're storing the object.
  147.         [self createReferenceFor: value];
  148.         [self writeString: NSStringFromClass([[value class])];
  149.         [value serializeUsing: self];
  150.     }
  151. }
  152. //  from Deserializer's code
  153. - (id) readObject
  154. {
  155. //  ....
  156. //  Here we need to exhume a previously unknown object.
  157.     Class classObjectForValue;
  158.     id value;
  159. classObjectForValue = NSClassFromString([self readNextString]);
  160.     if (nil!= classObjectForValue)
  161.     {
  162.         value=[[ classObjectForValue alloc] initFromSerializer: self];
  163.     }
  164.     else
  165.     {
  166. //  Bad thing happened here. Raise an exception because our data is corrupt.
  167. //      ...
  168.     }
  169.     return value;
  170. }
  171.  
  172. Listing Six
  173. //  header (.h) file
  174. #import <foundation/foundation.h>
  175. @interface CommandObject: NSObject
  176. {
  177.     id target;
  178.     id argument;
  179.     NSString * nameOfMethod;
  180.     SEL selectorForMethod;
  181. }
  182. - (void) dealloc;
  183. - init;
  184. - (void) setArgumentObject:  newArgument;
  185. - (void) setTargetObject:  newTarget;
  186.  
  187. //  Function overloading would make the next two methods more pleasant. 
  188. - (void) setTargetMethodByString: (NSString *) methodName;  
  189. - (void) setTargetMethodBySelector:  (SEL) methodSelector;
  190. - (bool) do;
  191. - (void) initWithCoder: (NSCoder *) decoder;
  192. - (void) encodeWithCoder: (NSCoder *) encoder;  
  193. @end
  194.  
  195. //  code (.m) file
  196. #import "CommandObject.h"
  197. @implementation CommandObject
  198. - (void) dealloc
  199. {
  200. //  retain, release, and autorelease are all part of reference counting.
  201. //  ref counting is in NEXTSTEP, but not part of the Objective-C spec.
  202. //  When an object's ref count goes to zero, it is deallocated.
  203.     [target autorelease];
  204.     [argument autorelease];
  205.     [nameOfMethod autorelease];
  206.     [super dealloc];
  207.     return;
  208. }
  209. - init
  210. {
  211. //  init is like a constructor. The object has already been 
  212. //  allocated and needs to have its variables initialized. 
  213.     [super init];
  214.     nameOfMethod=argument=target=nil;   //always safe cause messages to nil
  215.                         //don't cause problems. 
  216.     return self;                //note that the return value of init has to be 
  217.                         //specified, unlike the return value from a 
  218.                         //C++ constructor. 
  219. }
  220. - (void) setArgumentObject:  newArgument
  221. {
  222.     if (nil!=argument)
  223.     {
  224.         [argument autorelease];
  225.     }   
  226.     argument=newArgument;
  227.     [argument retain];
  228.     return;
  229. }
  230. - (void) setTargetObject:  newTarget
  231. {
  232.     if (nil!=target)
  233.     {
  234.         [target autorelease];
  235.     }   
  236.    target=newTarget;
  237.     [target retain];
  238.     return;
  239. }
  240. - (void) setTargetMethodByString: (NSString *) methodName
  241. {
  242.     nameOfMethod = [methodName copy];   //make our own copy
  243.                         //to guard against changes
  244.     selectorForMethod= NSSelectorFromString (nameOfMethod);
  245.     return;
  246. }
  247. - (void) setTargetMethodBySelector:  (SEL) methodSelector
  248. {
  249. selectorForMethod= methodSelector;
  250. nameOfMethod= [NSStringFromSelector (selectorForMethod) retain];
  251.     return;
  252. }
  253. - (bool) do
  254. {
  255.     if (YES==[target respondsTo: selectorForMethod])
  256.     {
  257.         [target perform: selectorForMethod];
  258.         return YES;
  259.     }
  260.     return NO;
  261. }
  262. - (void) initWithCoder: (NSCoder *) decoder
  263. {
  264. //  From target, object, and nameOfMethod, we can get selector back (in fact,
  265. //  we'll call function to do so). Hence, object graph can be fully restored. 
  266. //  ....
  267. }
  268. - (void) encodeWithCoder: (NSCoder *) encoder
  269. {
  270. //  We write out three objects--target, argument,and nameOfMethod. 
  271. //  this is just the "serialize" method discussed earlier.
  272. //  ...
  273. }
  274. @end
  275.  
  276.  
  277.